<template>
  <div ref="renderContainer"></div>
</template>

<script>
import * as THREE from 'three';
import Stats from 'three/examples/jsm/libs/stats.module.js';
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

export default {
  name: 'ThreeJSComponent',
  data() {
    return {
      camera: null,
      scene: null,
      renderer: null,
      controls: null,
      stats: null,
      mesh: null,
      amount: 10,
      count: Math.pow(this.amount, 3),
      raycaster: new THREE.Raycaster(),
      mouse: new THREE.Vector2(1, 1),
      color: new THREE.Color(),
      white: new THREE.Color().setHex(0xffffff)
    };
  },
  mounted() {
    this.initThreeJS();
  },
  methods: {
    initThreeJS() {
      const container = this.$refs.renderContainer;
      const width = container.clientWidth;
      const height = container.clientHeight;

      // 创建相机
      this.camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 100);
      this.camera.position.set(this.amount, this.amount, this.amount);
      this.camera.lookAt(0, 0, 0);

      // 创建场景
      this.scene = new THREE.Scene();

      // 创建光照
      const light = new THREE.HemisphereLight(0xffffff, 0x888888, 3);
      light.position.set(0, 1, 0);
      this.scene.add(light);

      // 创建几何形状和材质
      const geometry = new THREE.IcosahedronGeometry(0.5, 3);
      const material = new THREE.MeshPhongMaterial({ color: 0xffffff });

      // 创建实例化网格
      this.mesh = new THREE.InstancedMesh(geometry, material, this.count);

      let i = 0;
      const offset = (this.amount - 1) / 2;

      const matrix = new THREE.Matrix4();

      for (let x = 0; x < this.amount; x++) {
        for (let y = 0; y < this.amount; y++) {
          for (let z = 0; z < this.amount; z++) {
            matrix.setPosition(offset - x, offset - y, offset - z);
            this.mesh.setMatrixAt(i, matrix);
            this.mesh.setColorAt(i, this.color);
            i++;
          }
        }
      }

      this.scene.add(this.mesh);

      // 创建 GUI
      const gui = new GUI();
      gui.add(this.mesh, 'count', 0, this.count);

      // 创建渲染器
      this.renderer = new THREE.WebGLRenderer({ antialias: true });
      this.renderer.setPixelRatio(window.devicePixelRatio);
      this.renderer.setSize(width, height);
      container.appendChild(this.renderer.domElement);

      // 创建轨道控制
      this.controls = new OrbitControls(this.camera, this.renderer.domElement);
      this.controls.enableDamping = true;
      this.controls.enableZoom = false;
      this.controls.enablePan = false;

      // 创建性能统计信息
      this.stats = new Stats();
      document.body.appendChild(this.stats.dom);

      window.addEventListener('resize', this.onWindowResize);
      document.addEventListener('mousemove', this.onMouseMove);

      this.animate();
    },
    onWindowResize() {
      const width = this.$refs.renderContainer.clientWidth;
      const height = this.$refs.renderContainer.clientHeight;
      this.camera.aspect = width / height;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(width, height);
    },
    onMouseMove(event) {
      event.preventDefault();
      this.mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
      this.mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    },
    animate() {
      requestAnimationFrame(this.animate);
      this.controls.update();
      this.raycaster.setFromCamera(this.mouse, this.camera);
      const intersection = this.raycaster.intersectObject(this.mesh);
      if (intersection.length > 0) {
        const instanceId = intersection[0].instanceId;
        this.mesh.getColorAt(instanceId, this.color);
        if (this.color.equals(this.white)) {
          this.mesh.setColorAt(instanceId, this.color.setHex(Math.random() * 0xffffff));
          this.mesh.instanceColor.needsUpdate = true;
        }
      }
      this.renderer.render(this.scene, this.camera);
      this.stats.update();
    }
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.onWindowResize);
    document.removeEventListener('mousemove', this.onMouseMove);
  }
};
</script>

<style>
#renderContainer {
  width: 100%;
  height: 100vh;
}
</style>
